package server;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;

import Servlet.Servlet;

import utils.Request;
import utils.Response;




public class ServerThread extends Thread{
	
	private static int clientCount  = 0 ;
	private Socket s = null;
	private DataInputStream ins = null;
	private DataOutputStream ous;
	private FileInputStream fins = null;
	private URLConnection urlCon = null;
	private Request request = null;

	
	
	
	public ServerThread(Socket s) {
		this.s = s;
		request  = new Request();
		clientCount++;
		
		System.out.println("connect client count:"+clientCount);
		
		try {
		
			ins = new DataInputStream(s.getInputStream());
			ous = new DataOutputStream(s.getOutputStream());
			
		} catch (IOException e) {

			e.printStackTrace();
		}
	}

	@Override
	public void run() {

		byte[] buffer = new byte[1024];
		StringBuffer strBuffer = new StringBuffer();
		String str = null;
		boolean isEnd = false;
		int count = 0;

		try {

			count = ins.read(buffer);

			request.setMethod(new String(buffer, 0, 4).trim());
			System.out.println("requset method : " + request.getMethod());

			request.setPath(getRequestPath(buffer, count));
			System.out.println("request Path :" + request.getPath());

			if (request.getMethod().equalsIgnoreCase("get")) {

				if (buffer[count - 2] == 13 && buffer[count - 1] == 10
						&& buffer[count - 4] == 13 && buffer[count - 3] == 10) {

					strBuffer.append(new String(buffer, 0, count));
					isEnd = true;
				}
				while (!isEnd) {

					count = ins.read(buffer);

					if (buffer[count - 2] == 13 && buffer[count - 1] == 10
							&& buffer[count - 4] == 13
							&& buffer[count - 3] == 10) {

						strBuffer.append(new String(buffer, 0, count));
						break;

					}

					strBuffer.append(new String(buffer, 0, count));

				}

				request.setHead(strBuffer.toString());

			} else if (request.getMethod().equalsIgnoreCase("post")) {

				String strTemp = new String(buffer, 0, count);
				StringBuffer bufBody = new StringBuffer();

				if (strTemp.indexOf("\r\n\r\n") == -1) {
					// http head not end
					strBuffer.append(strTemp);
					while (true) {

						count = ins.read(buffer);
						strTemp = new String(buffer, 0, count);

						if (strTemp.indexOf("\r\n\r\n") != -1) {

							strBuffer.append(strTemp.substring(0, strTemp
									.indexOf("\r\n\r\n") + 4));

							request.setHead(strBuffer.toString());

							bufBody.append(strTemp.substring(strTemp
									.indexOf("\r\n\r\n") + 4, count));
							request
									.setContentLength(getRequestContentLength(request
											.getHead()));
							break;
						}

					}

				} else if (strTemp.indexOf("\r\n\r\n") != -1) {

					strBuffer.append(strTemp.substring(0, strTemp
							.indexOf("\r\n\r\n") + 4));

					request.setHead(strBuffer.toString());

					bufBody.append(strTemp.substring(strTemp
							.indexOf("\r\n\r\n") + 5, count));
					request.setContentLength(getRequestContentLength(request
							.getHead()));

				}

				int readedLength = bufBody.toString().length();

				while (readedLength < request.getContentLength()) {
					count = ins.read(buffer);
					readedLength += count;
					bufBody.append(new String(buffer,0,count));

				}
				
				request.setBody(bufBody.toString());
				System.out.println(request.getBody());
				
				getRequestParas(request);

			

			}
			
			//  if  request a servlet 
			
			String path  = request.getPath() ;
			if(path.substring(1, path.indexOf("/")).equalsIgnoreCase("serlvet")){
				
				servletResponse(request);
			}
			
			response(request.getPath());

		} catch (IOException e) {

			e.printStackTrace();

		} finally {
			try {
				if (ins != null) {

					ins.close();

					ins = null;
				}
				if (ous != null) {
					ous.close();
					ous = null;
				}
			} catch (IOException e) {
		
				e.printStackTrace();
			}

		}

	}
	


	private void servletResponse(Request request) {
		
	
		File dir  =new File("/home/chunk/code/server/servlet");
		String str   =  request.getPath().substring(1);
		if(str.indexOf("?")!=-1){
			str = str.substring(0,str.indexOf("?"));
		}
		
		
		URI uri = dir.toURI();
		
		try {
			URL url = uri.toURL();
			URL [] urls = {url};
			
			ClassLoader cl  = new URLClassLoader(urls);
			Class cls = cl.loadClass(str);
			Servlet servlet = (Servlet) cls.newInstance();
			
			if(request.getMethod().equalsIgnoreCase("get")){
				
				servlet.doGet(request, new Response());
				
			}else if(request.getMethod().equalsIgnoreCase("post")){
				
				servlet.doPost(request, new Response());
			}
			
			
		} catch (MalformedURLException e1) {
	
			e1.printStackTrace();
		} catch (ClassNotFoundException e) {

			e.printStackTrace();
		} catch (InstantiationException e) {

			e.printStackTrace();
		} catch (IllegalAccessException e) {
		
			e.printStackTrace();
		}
		
		
	
		
		
		
	}

	private void getRequestParas(Request request) {

		// just do when method equals post

		String temp = request.getBody();
	
		String[] key_value = temp.split("&");

		for (int i = 0; i < key_value.length; i++) {
			String[] key_value1 = key_value[i].split("=");
			request.getParameters().put(key_value1[0], key_value1[1]);
		}

	}

	private int getRequestContentLength(String head) {
		
		String temp1  = head.substring(head.indexOf("Content-Length:"));
		String temp2 = temp1.substring(15,temp1.indexOf("\r\n")).trim();
		
		int value = Integer.valueOf(temp2);
		
		
		
		return value;
	}



	private void response(String strAbsPath) {
		
		
		String path = "/home/chunk/code/server" + strAbsPath;
		String strType =  null;
		
		
		System.out.println("the type :"+strAbsPath.substring(strAbsPath.indexOf(".")));
		if(strAbsPath.substring(strAbsPath.indexOf(".")).equalsIgnoreCase(".html")){
			strType= "text/html";
		}else if(strAbsPath.substring(strAbsPath.indexOf(".")).equalsIgnoreCase(".image")){
			strType= "image/gif";
			
		}
		

		File file = new File(path);

		byte[] buffer = new byte[1024];
		int count = 0;

		Date date = new Date(System.currentTimeMillis());
		SimpleDateFormat dateFormate = new SimpleDateFormat("MM:dd:yyyy");
		String strDate = dateFormate.format(date);

		try {

			if (!file.exists()) {

				return;

			}

			fins = new FileInputStream(file);

			ous.writeBytes("HTTP/1.1 200 OK\r\n");
			ous.writeBytes("Server: Self-Server\r\n");
			ous.writeBytes("Accept-Ranges: bytes\r\n");
			ous.writeBytes("Content-Type: "+strType+"\r\n");
			ous.writeBytes("Expires:" + strDate + "\r\n");
			ous.writeBytes("Content-Length:" + file.length() + "\r\n");
			ous.writeBytes("\r\n");

			while (true) {

				count = fins.read(buffer);

				if (count == -1) {
					break;
				}

				ous.write(buffer, 0, count);

			}
			ous.flush();
			fins.close();

		} catch (IOException e) {

			e.printStackTrace();
		}

	}



	private String getRequestPath(byte[] buffer, int length) {

		String buff = null;
		String strEncode = null;
		try {
			strEncode = java.net.URLDecoder.decode(new String(buffer), "utf-8");

		} catch (UnsupportedEncodingException e1) {

			e1.printStackTrace();
		}

		if (request.getMethod().equalsIgnoreCase("get")) {
			buff = new String(strEncode.getBytes(), 4, length);

			String temp = buff.substring(0, buff.indexOf(" ")).trim();

			if (temp.indexOf("?") != -1) {
				
				String temp1 = temp.substring(0, temp.indexOf("?"));
				String temp2 = temp.substring(temp.indexOf("?") + 1);
				
				String[] key_value = temp2.split("&");
				
				for(int i = 0 ;i<key_value.length;i++){
					String[] key_value1  = key_value[i].split("=");
					request.getParameters().put(key_value1[0],key_value1[1]);
				}
				
				return temp1;

			}

			return buff.substring(0, buff.indexOf(" ")).trim();
		} else {
			buff = new String(strEncode.getBytes(), 5, length);
		}

		return buff.substring(0, buff.indexOf(" ")).trim();

	}
	


	
}
